package com.ai.vita.template;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.*;

/**
 * Created by yangyj on 2016/3/11.
 */
public class TemplateLoader implements ApplicationContextAware {

    private static TemplateLoader loader;

    public void setApplicationContext(ApplicationContext a) {
        loader = (TemplateLoader)a.getBean("templateLoader");
    }

    /**    模版内容      **/
    private static HashMap<String,String> resources = new HashMap<String,String>();

    private static HashMap<String,String> paths = new HashMap<String, String>();

    private static HashMap<String,Long> lastModify = new HashMap<String, Long>();

    public static boolean containTemplate(String... tInfo){
        String name = getRealTemplateName(tInfo);
        return resources.get(name) != null ? true : false;
    }

    public static String getTemplate(String... tInfo){
        String template, name = getRealTemplateName(tInfo);
        if(loader.isRealTime()){
            String path = paths.get(name);
            if(path != null){
                //实时更新
                Resource[] re = loader.getResources(path);
                for(int rIndex = 0;rIndex < re.length;rIndex++){
                    Resource r = re[rIndex];
                    Long time = lastModify.get(name);
                    try {
                        if(time == null || r.lastModified() > time){
                            loader.handleResource(r);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        template = resources.get(name);
        return template;
    }

    public static String getTemplatePath(String... tInfo){
        String name = getRealTemplateName(tInfo);
        return paths.get(name);
    }

    /**
     * 生成完整的模版名称
     * @param params 0：模版名称，1：扩展名，2：设备类型（按设备推送的界面标识）
     * @return 组装好的文件名
     * @throws Exception
     */
    public static String getRealTemplateName(String... params) {
        String name = params[0], extName = params[1], deviceType = "";
        if(params.length > 2){
            deviceType = params[2];
        }
        StringBuffer realName = new StringBuffer();
        realName.append(name);
        if(deviceType != null && !"".equals(deviceType)){
            realName.append(".").append(deviceType);
        }
        if(loader.isMinified()){
            realName.append(".").append(loader.getMinifiedExt());
        }
        realName.append(".").append(extName);
        return realName.toString();
    }

    public static String getProperties(String key){
        if(loader.getProperties() == null){
            return null;
        }else{
            return loader.getProperties().get(key);
        }
    }

    public static String getNotFoundPrompt(){
        return loader.getTemplateNotFound();
    }

    /**        参数设置        **/
    public void setResourcePaths(String[] resourcePaths) {
        this.resourcePaths = new String[resourcePaths.length];
        System.arraycopy(resourcePaths, 0, this.resourcePaths, 0, resourcePaths.length);
        //this.resourcePaths = resourcePaths;
    }

    private String[] resourcePaths;


    public boolean isRealTime() {
        return realTime;
    }

    public void setRealTime(boolean realTime) {
        this.realTime = realTime;
    }

    private boolean realTime;

    public String getFilter() {
        return filter;
    }

    public void setFilter(String filter) {
        this.filter = filter;
    }

    private String filter;

    public boolean hasSubDirectory() {
        return subDirectory;
    }

    public void setSubDirectory(boolean subDirectory) {
        this.subDirectory = subDirectory;
    }

    private boolean subDirectory;

    public boolean isMinified() {
        return minified;
    }

    public void setMinified(boolean minified) {
        this.minified = minified;
    }

    private boolean minified;

    public String getMinifiedExt() {
        return minifiedExt;
    }

    public void setMinifiedExt(String minifiedExt) {
        this.minifiedExt = minifiedExt;
    }

    private String minifiedExt = "min";

    public Map<String, String> getProperties() {
        return properties;
    }

    public void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }

    private Map<String, String> properties;

    private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private String templateNotFound = "没有找到指定模版（_templateName_），请确认模版路径！";

    public String getTemplateNotFound() {
        return templateNotFound;
    }

    public void setTemplateNotFound(String templateNotFound) {
        this.templateNotFound = templateNotFound;
    }

    /**        资源读取          **/
    public void init() {
        if(resourcePaths != null && resourcePaths.length > 0){
            ArrayList<Resource> resources = new ArrayList<Resource>();
            int resIndex = 0;
            //过滤用的扩展名
            String[] filters = filter != null && !"".equals(filter) ? filter.split(",") : new String[0];
            for(;resIndex < resourcePaths.length;resIndex++){
                String r = resourcePaths[resIndex];
                if(r.split("\\.").length > 1){
                    //带有文件名
                    String fileName = r.substring(r.lastIndexOf("/") + 1);
                    if(filters.length == 0 || Arrays.binarySearch(filters, fileName.split("\\.")[1]) > -1){
                        //没有限制扩展名 或者 限制扩展名且扩展名在允许范围内，去获取资源
                        Resource[] re = getResources(r);
                        Collections.addAll(resources,re);
                    }
                }else{
                    //不带文件名
                    if(!r.endsWith("/")){
                        r += "/";
                    }
                    //处理子目录
                    if(hasSubDirectory()){
                        r += "**/";
                    }
                    if(filters.length > 0){
                        for(int fIndex = 0;fIndex < filters.length;fIndex++){
                            Resource[] re = getResources(r + "*." + filters[fIndex]);
                            Collections.addAll(resources,re);
                        }
                    }else{
                        Resource[] re = getResources(r + "*.*");
                        Collections.addAll(resources,re);
                    }
                }
            }
            handleResource(resources);
        }
    }

    /**
     * 根据path获取资源
     * @param path
     * @return
     */
    private Resource[] getResources(String path){
        try {
            return resourcePatternResolver.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 处理资源
     * @param rs
     */
    private void handleResource(ArrayList<Resource> rs){
        handleResource(rs.toArray(new Resource[0]));
    }

    /**
     * 处理资源
     * @param rs
     */
    private void handleResource(Resource[] rs){
        for(int index = 0;index < rs.length;index++){
            Resource r = rs[index];
            handleResource(r);
        }
    }

    /**
     * 处理资源
     * @param r
     */
    private void handleResource(Resource r){
        if(r.exists() && r.isReadable()) {
            Reader reader = null;
            try{
                String fileName = r.getFilename();
                reader = new InputStreamReader(r.getInputStream(),"UTF-8");
                int tempChar;
                StringBuffer b = new StringBuffer();
                while ((tempChar = reader.read()) != -1) {
                    // 对于windows下，\r\n这两个字符在一起时，表示一个换行。
                    // 但如果这两个字符分开显示时，会换两次行。
                    // 因此，屏蔽掉r，或者屏蔽n。否则，将会多出很多空行。
                    if (((char) tempChar) != '\r') {
                        b.append((char) tempChar);
                    }
                }
                String tb = b.toString();
                //如果等于""，则是目录
                if(!"".equals(tb)){
                    resources.put(fileName, tb);
                    String path = r.getURL().getPath();
                    if(path.indexOf("jar!/") > -1){
                        //weblogic中war发布方式，从jar里取
                        path = path.split("jar!/")[1];
                    }else if (path.indexOf("/classes/") > -1){
                        //目录解压发布方式，从classes目录里取
                        path = path.split("/classes/")[1];
                    }
                    paths.put(fileName, path);
                    lastModify.put(fileName, r.lastModified());
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                if(reader != null){
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}